#include "Client.h"
#include "Buffer.h"
#include "Mutex.h"
#include "Event.h"
#include "Threadpool.h"

Client::Client(int id, Network::Connection*	cnt)
: _id(id), _cnt(cnt), _availableToSend(0), _sendLoop(true)
{
	this->_buff = new Buffer(20000);
	this->_buffSend = new Buffer(20000);
	this->_lockSend = new Mutex();
	this->_eventBuffer = new Event();
	this->_eventDestructor = new Event();

	ThreadPool::Request *rqt = new ThreadPool::Request();
	rqt->function = &Client::SendData;
	rqt->autoFree = true;
	rqt->parameters = this;
	ThreadPool::GetThreadPool()->AddRequest(rqt);
}

Client::~Client()
{
	this->_sendLoop = false;
	this->_eventBuffer->Set();
	this->_eventDestructor->Wait();
	delete this->_buff;
	delete this->_buffSend;
	delete this->_lockSend;
	delete this->_eventBuffer;
	delete this->_eventDestructor;
}

IBuffer* Client::GetBuffer()
{
	return (this->_buff);
}

Network::Connection*	Client::GetConnection()
{
	return (this->_cnt);
}

int	Client::GetId()
{
	return (this->_id);
}

unsigned int	Client::SendBuffer(void* data, unsigned int size)
{
	this->_lockSend->Lock();
	if (this->_buffSend->SizeMax() - this->_buffSend->Size() < size)
	{
		this->_lockSend->Unlock();
		return (1);
	}
	if (this->_buffSend->Write(data, size) >= 0)
	{
		this->_availableToSend += size;
		this->_eventBuffer->Set();
	}
	this->_lockSend->Unlock();
	return (0);
}

void	Client::SendData(void* client)
{
	Client*			clt = reinterpret_cast<Client*>(client);
	unsigned int	size;
	unsigned int	sentSize;
	void*			data;
	timeval			tm;


	while (clt->_sendLoop)
	{
		clt->_eventBuffer->Wait();
		clt->_lockSend->Lock();
		size = clt->_availableToSend;
		clt->_lockSend->Unlock();
		data = clt->_buffSend->Read(size, false);
		tm.tv_sec = 1;
		tm.tv_usec = 0;
		sentSize = size;
		clt->_cnt->SendData(data, &sentSize, &tm);
		
		clt->_lockSend->Lock();
		if (sentSize == clt->_availableToSend)
		{
			clt->_eventBuffer->Reset();
		}
		clt->_availableToSend -= sentSize;
		clt->_buffSend->Delete(sentSize);
		clt->_lockSend->Unlock();
	}
	clt->_eventDestructor->Set();
}